#include <iostream>
#include <string>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

using namespace std;


#define PAGE_SIZE 4096              // 内存4k大小

using uchar = unsigned char;

//对齐规则
#define MP_ALIGNMENT 16
#define mp_align(n, alignment) (((n) + (alignment - 1)) & ~(alignment - 1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p) + (alignment - 1)) & ~(alignment - 1))


class Mem_node
{
public:
    //初始化node结点
    void init();
    //将node结点置回初始状态
    void node_clean();
    //分配成功，引用计数+1，移动start指针
    void node_malloc(size_t size);
    //减少引用计数，若为0移动start指针
    void node_free();
    uchar * get_start();
    uchar * get_end();
    int get_quote();
    //获取end - start的值，也就是当前块现在的可用长度
    size_t get_len();
    Mem_node *get_next();
    //每次调用get方法failed计数器自增1
    int get_failed();
    void set_next(Mem_node* next);

private:
    uchar *m_start;  //标记当前标准块可以使用的起始地址
    uchar *m_end;   //标记当前标准块可以使用的末尾地址
    Mem_node *m_next;   //标准快链表的next指针
    int m_quote;       //当前标准块的引用计数器，用来判断当前标准块是否被使用
    int m_failed;        //当前标准块的错误计数器，用来移动内存池的current指针提高效率
};


class Mem_large
{
public:
    //使large结点的成员变量重置为参数所示的值
    void large_reset(int size,void * alloc);
    //释放掉large结点指向的自定义块内存空间
    void large_free();
    void set_next(Mem_large * next);
    Mem_large * get_next();
    void * get_alloc();
    int get_size();
private:
    Mem_large *m_next;            //自定义块链表的next指针
    int m_size;                  //用来存放自定义块所占用的内存大小
    void *m_alloc;               //用来存放自定义块所在的起始地址
};


class Mem_pool
{
public:
    Mem_pool() = delete;

    //构造函数，创建内存池，并初始化一块自定义大小的空间
    explicit Mem_pool(size_t size); //类型转化构造函数，自定义的大小仅允许是4k的整数倍

    //析构函数，销毁内存池，遍历各个标准块与大块，把从堆区分配的内存释放
    ~Mem_pool();

    //给用户提供的申请内存空间的接口
    void *mp_new(size_t size);

    //给用户提供的申请内存空间的接口，并全部初始化为0
    void *mp_new_zero(size_t size);

    //给用户提供的释放已申请的内存空间的接口
    void mp_delete(void *p);

    //给用户提供的清空内存池中数据的接口
    void mp_reset_pool();

    //给用户提供的显示当前内存池使用情况的接口
    void mp_monitor(string msg);

private:
    //向堆空间申请一块标准块空间
    void *mp_new_block(size_t size);

    //向堆空间申请一块长度大于标准块长度的自定义大块空间
    void *mp_new_large(size_t size);

    Mem_node *m_head;    //标准块链表的头指针
    Mem_node *m_current; //标准块链表当前可能使用的指针（局部性原理）
    Mem_large *m_large;  //大块链表的头指针
};
